﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Telerik.Windows.Documents.Fixed.FormatProviders.Pdf;
using Telerik.Windows.Documents.Fixed.Model;
using Telerik.Windows.Documents.Fixed.Model.ColorSpaces;
using Telerik.Windows.Documents.Fixed.Model.Editing;
using Telerik.Windows.Documents.Fixed.Model.Editing.Flow;
using Telerik.Windows.Documents.Fixed.Model.Editing.Tables;
using Telerik.Windows.Documents.Flow.FormatProviders.Html;
using Telerik.Windows.Documents.Flow.Model;
using Telerik.Windows.Documents.Flow.Model.Shapes;

namespace Console_4._7._2
{
    internal class Program
    {
        static void Main(string[] args)
        {
            RadFlowDocument htmlDocument;
            HtmlFormatProvider htmlFormatProvider = new HtmlFormatProvider();
            HtmlImportSettings importSettings = new HtmlImportSettings();

            importSettings.LoadImageFromUri += (s, e) =>
            {
                System.Net.WebClient webClient = new System.Net.WebClient();
                byte[] data = webClient.DownloadData(e.Uri);

                string extension = System.IO.Path.GetExtension(e.Uri).Substring(1);
                e.SetImageInfo(data, extension);
            };

            htmlFormatProvider.ImportSettings = importSettings;

            using (Stream input = File.OpenRead(@"C:\Users\ykaraman\Desktop\DocumentExample.html"))
            {
                htmlDocument = htmlFormatProvider.Import(input, null);
            }

            Telerik.Windows.Documents.Flow.Model.Table htmlTable = htmlDocument.EnumerateChildrenOfType<Telerik.Windows.Documents.Flow.Model.Table>().FirstOrDefault();

            RadFixedDocument maindPdfDocument = new RadFixedDocument();
            
            // Convert HTML table rows to a list for easier processing
            var htmlRowsList = htmlTable.Rows.ToList();
            int currentRowIndex = 0;

            while (currentRowIndex < htmlRowsList.Count)
            {
                RadFixedPage pdfPage = maindPdfDocument.Pages.AddPage();
                FixedContentEditor pdfPageEditor = new FixedContentEditor(pdfPage);

                Telerik.Windows.Documents.Fixed.Model.Editing.Tables.Table pdfTable = CreateNewTable(pdfPage);
                
                int rowsAddedToCurrentTable = 0;

                // Add rows to the current table until it exceeds page height
                while (currentRowIndex < htmlRowsList.Count)
                {
                    var htmlRow = htmlRowsList[currentRowIndex];
                    
                    // Create a temporary table to test if adding this row would exceed page height
                    Telerik.Windows.Documents.Fixed.Model.Editing.Tables.Table testTable = CreateNewTable(pdfPage);
                    
                    // Copy existing rows to test table
                    for (int i = currentRowIndex - rowsAddedToCurrentTable; i < currentRowIndex; i++)
                    {
                        if (i >= 0)
                        {
                            AddRowToTable(testTable, htmlRowsList[i], pdfPage);
                        }
                    }
                    
                    // Add the new row to test table
                    AddRowToTable(testTable, htmlRow, pdfPage);

                    // Measure the test table
                    var testTableSize = testTable.Measure();
                    
                    // Check if table exceeds page height (leaving some margin)
                    if (testTableSize.Height > pdfPage.Size.Height - 40 && rowsAddedToCurrentTable > 0) // 40 points margin
                    {
                        break; // Start a new page - don't add this row to current table
                    }
                    
                    // Add the row to the actual table
                    AddRowToTable(pdfTable, htmlRow, pdfPage);
                    rowsAddedToCurrentTable++;
                    currentRowIndex++;
                }

                // Draw the table on the current page
                pdfPageEditor.DrawTable(pdfTable);
            }

            RadFixedDocument backgroundDocument;
            PdfFormatProvider pdfProvider = new PdfFormatProvider();

            using (Stream input = File.OpenRead("..\\..\\..\\background.pdf"))
            {
                backgroundDocument = pdfProvider.Import(input, null);
            }

            foreach (RadFixedPage page in maindPdfDocument.Pages)
            {
                // Get the background page (using first page of background document)
                RadFixedPage backgroundPage = backgroundDocument.Pages.First();
                
                // Store existing content elements in a temporary list
                var existingContent = new List<Telerik.Windows.Documents.Fixed.Model.ContentElementBase>();
                foreach (var element in page.Content)
                {
                    existingContent.Add(element);
                }
                
                // Clear the current page content
                page.Content.Clear();
                
                // First, add all content elements from the background page
                foreach (var backgroundElement in backgroundPage.Content)
                {
                    page.Content.Add(backgroundElement);
                }
                
                // Then, add back all existing content elements
                foreach (var element in existingContent)
                {
                    page.Content.Add(element);
                }
            }

            File.Delete("..\\..\\..\\output.pdf");
            using (Stream output = File.Create("..\\..\\..\\output.pdf"))
            {
                pdfProvider.Export(maindPdfDocument, output, null);
            }

            var psi = new ProcessStartInfo()
            {
                FileName = "..\\..\\..\\output.pdf",
                UseShellExecute = true
            };
            Process.Start(psi);
        }

        private static Telerik.Windows.Documents.Fixed.Model.Editing.Tables.Table CreateNewTable(RadFixedPage pdfPage)
        {
            Telerik.Windows.Documents.Fixed.Model.Editing.Tables.Table pdfTable = new Telerik.Windows.Documents.Fixed.Model.Editing.Tables.Table();
            Border blackBorder = new Border(2, new RgbColor(0, 0, 0));
            pdfTable.DefaultCellProperties.Borders = new TableCellBorders(blackBorder, blackBorder, blackBorder, blackBorder);
            pdfTable.Margin = new System.Windows.Thickness(10, 10, 10, 10);
            return pdfTable;
        }

        private static void AddRowToTable(Telerik.Windows.Documents.Fixed.Model.Editing.Tables.Table pdfTable, Telerik.Windows.Documents.Flow.Model.TableRow htmlRow, RadFixedPage pdfPage)
        {
            Telerik.Windows.Documents.Fixed.Model.Editing.Tables.TableRow pdfRow = pdfTable.Rows.AddTableRow();

            foreach (var htmlCell in htmlRow.Cells)
            {
                var pdfCell = pdfRow.Cells.AddTableCell();

                if (htmlRow.Cells.IndexOf(htmlCell) == 0)
                {
                    pdfCell.PreferredWidth = pdfPage.Size.Width * 0.10;
                }
                else if (htmlRow.Cells.IndexOf(htmlCell) == 1)
                {
                    pdfCell.PreferredWidth = pdfPage.Size.Width * 0.80;
                }

                foreach (var htmlBlock in htmlCell.Blocks)
                {
                    var pdfBlock = pdfCell.Blocks.AddBlock();

                    if (htmlBlock is Paragraph htmlParagraph)
                    {
                        foreach (var htmlInline in htmlParagraph.Inlines)
                        {
                            if (htmlInline is ImageInline htmlImageInline)
                            {
                                using (MemoryStream stream = new MemoryStream(htmlImageInline.Image.ImageSource.Data))
                                {
                                    var imageSource = new Telerik.Windows.Documents.Fixed.Model.Resources.ImageSource(stream);
                                    pdfBlock.InsertImage(imageSource);
                                }
                            }
                            else if (htmlInline is Run run)
                            {
                                pdfBlock.InsertText(run.Text);
                            }
                            else if (htmlInline is Break)
                            {
                                pdfBlock.InsertLineBreak();
                            }
                        }
                    }
                }
            }
        }
    }
}
